/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */
package com.pig4cloud.pigx.contract.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import com.pig4cloud.pigx.contract.constant.ContractKLineConstants;
import com.pig4cloud.pigx.contract.dto.AppContractKLineListDTO;
import com.pig4cloud.pigx.contract.entity.ContractKLine;
import com.pig4cloud.pigx.contract.mapper.ContractKLineMapper;
import com.pig4cloud.pigx.contract.mongo.entity.ContractKLineMongo;
import com.pig4cloud.pigx.contract.service.ContractKLineService;
import com.pig4cloud.pigx.contract.thread.repair.RepairKLine;
import com.pig4cloud.pigx.contract.utils.HttpUtils;
import lombok.AllArgsConstructor;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;

import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * k线数据表
 *
 * @date 2022-08-13 19:50:37
 */
@Service
@AllArgsConstructor
public class ContractKLineServiceImpl extends ServiceImpl<ContractKLineMapper, ContractKLine> implements ContractKLineService {

	private final MongoTemplate mongo;

	private final RepairKLine repairKLine;

	private final static int LIMIT = 500;

	@Override
	public List<List<Object>> getKLineList(AppContractKLineListDTO data) {
		Integer querySize = data.getQuerySize();
		// mongo缓存最多500条，如果本次查询量超出范围，则走mysql查询
		Long endTime = data.getEndTime();
		if (endTime != null) {
			LocalDateTime time = Instant.ofEpochMilli(endTime).atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
			data.setEndDateTime(time);
		}
		List<ContractKLine> list;
		if (endTime == null) {
			// mongo
			list = this.doMongoSelect(data);
		} else {
			// mysql
			String tableName = ContractKLineConstants.findByTimeRangeType(data.getType()).getTableName();
			data.setTableName(tableName);
			list = baseMapper.selectKLineList(data);
		}
		// 数据不全上币安补
		try {
			if (list.size() < LIMIT) {
				list = getBiAn(data,list);
			}
		} catch (Exception e) {
			return getList(list);
		}
		return getList(list);
	}

	private List<List<Object>> getList(List<ContractKLine> lines) {
		List<List<Object>> data = new ArrayList<>();
		for (ContractKLine line : lines) {
			List<Object> list = new ArrayList<>();
			list.add(line.getStartTime().toInstant(ZoneOffset.ofHours(8)).toEpochMilli());
			list.add(line.getOpenPrice());
			list.add(line.getHighPrice());
			list.add(line.getLowPrice());
			list.add(line.getClosePrice());
			list.add(line.getDealNum());
			list.add(line.getEndTime().toInstant(ZoneOffset.ofHours(8)).toEpochMilli());
			// 涨跌额
			BigDecimal subtract = line.getClosePrice().subtract(line.getOpenPrice());
			if (subtract.compareTo(BigDecimal.ZERO) < 0) {
				list.add(subtract.negate());
			} else {
				list.add(subtract);
			}
			// 涨跌幅
			BigDecimal divide = subtract.multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).divide(line.getOpenPrice(),2,BigDecimal.ROUND_HALF_UP);
			list.add(divide);
			list.add(line.getDealPrice());
			list.add("0");
			list.add("0");
			data.add(list);
		}
		return data;
	}

	private List<ContractKLine> doMongoSelect(AppContractKLineListDTO data) {
		String collectionName = data.getSymbolName() + "_" + data.getType();
		Query query = new Query();
		query.with(Sort.by(Sort.Order.asc("startTime")));
		if (data.getEndDateTime() != null) {
			query.addCriteria(Criteria.where("startTime").lt(data.getEndDateTime()));
		}
		query.limit(data.getQuerySize());
		List<ContractKLine> kLines = mongo.find(query, ContractKLine.class, collectionName);
		return kLines;
	}

	private List<ContractKLine> getBiAn(AppContractKLineListDTO data,List<ContractKLine> kLines) {
		List<ContractKLine> list = new ArrayList<>();
		String url = "";
		if (kLines.size() == 0) {
			url = RepairKLine.getUrl(
					data.getSymbolName(),
					Objects.requireNonNull(ContractKLineConstants.findByTimeRangeType(data.getType())).getBiAnLineType(),
					LIMIT,
					null,
					data.getEndTime() - 1
			);
		} else {
			url = RepairKLine.getUrl(
					data.getSymbolName(),
					Objects.requireNonNull(ContractKLineConstants.findByTimeRangeType(data.getType())).getBiAnLineType(),
					LIMIT - kLines.size(),
					null,
					RepairKLine.toTimeStamp(kLines.get(0).getStartTime()) - 1
			);
		}
		List<List<Object>> request;
		try {
			request = (List<List<Object>>) HttpUtils.sendGetRequest(url, new LinkedMultiValueMap<>());
		} catch (Exception e) {
			request = new ArrayList<>();
		}
		request.forEach(e -> {
			ContractKLineMongo lineMongo = repairKLine.getContractKLineMongo(e, data.getSymbolId(), data.getSymbolName());
			ContractKLine kLine = new ContractKLine();
			BeanUtils.copyProperties(lineMongo,kLine);
			list.add(kLine);
		});
		list.addAll(kLines);
		return list;
	}
}
